package com.bzkj.msfx.utils;

import com.alibaba.fastjson2.JSONObject;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.page.TableDataInfo;
import com.bzkj.common.core.redis.RedisCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Fusion系统HTTP请求工具类
 *
 * @author chj
 */
@Component
public class FusionHttpUtils {
    private static final Logger logger = LoggerFactory.getLogger(FusionHttpUtils.class);

    private static final String BOUNDARY = "----WebKitFormBoundary7MA4YWxkTrZu0gW";
    private static final String TOKEN_KEY = "wms:fusion:token";
    private static final String TOKEN_EXPIRE_KEY = "wms:fusion:token";
    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String BEARER_PREFIX = "Bearer ";
    private static final String CONTENT_TYPE_HEADER = "Content-Type";
    private static final String MULTIPART_FORM_DATA = "multipart/form-data; boundary=" + BOUNDARY;
    private static final String JSON_CONTENT_TYPE = "application/json; utf-8";
    private static final String WMS_TOKEN_KEY = "wms:fusion:token";
    @Resource
    private RedisCache redisCache;

    @Value("${msfx-fusion.baseUrl}")
    private String fusionUrl;

    /**
     * 上传文件到融合系统
     *
     * @param multipartFile 文件上传
     * @param path          接口路径
     * @return 请求结果
     * @throws IOException 文件转换异常
     */
    public AjaxResult sendFiles(MultipartFile multipartFile, String path) throws IOException {
        String token = redisCache.getCacheObject(TOKEN_KEY);
        if (token == null) {
            throw new IllegalStateException("Token not found in Redis");
        }

        URL url = new URL(fusionUrl + path);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        try {
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            connection.setRequestProperty(AUTHORIZATION_HEADER, BEARER_PREFIX + token);
            connection.setRequestProperty(CONTENT_TYPE_HEADER, MULTIPART_FORM_DATA);

            try (OutputStream outputStream = connection.getOutputStream();
                 PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), true);
                 InputStream fileInputStream = multipartFile.getInputStream()) {

                // 写入文件头
                writer.append("--").append(BOUNDARY).append("\r\n");
                writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"")
                        .append(multipartFile.getOriginalFilename()).append("\"\r\n");
                writer.append("Content-Type: ").append(multipartFile.getContentType()).append("\r\n\r\n");
                writer.flush();

                // 写入文件内容
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                outputStream.flush();

                // 结束请求体
                writer.append("\r\n--").append(BOUNDARY).append("--\r\n");
                writer.flush();
            }

            try (BufferedReader in = new BufferedReader(
                    new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {

                StringBuilder response = new StringBuilder();
                String inputLine;
                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }

                logger.debug("Response from fusion system: {}", response);
                return checkToken(response.toString());

            }

        } finally {
            connection.disconnect();
        }
    }

    /**
     * 获取表格数据
     *
     * @param path   请求地址
     * @param params 请求参数
     * @return 表格数据
     * @throws RuntimeException 当请求失败时抛出
     */
    public TableDataInfo getTableDataInfo(String path, Object params) throws RuntimeException {
        String token = redisCache.getCacheObject(TOKEN_EXPIRE_KEY);
        if (token == null) {
            throw new IllegalStateException("Token not found in Redis");
        }

        try {
            String queryParams = convertToQueryString(params);
            logger.debug("Request parameters: {}", queryParams);

            String fullUrl = fusionUrl + path + (queryParams.isEmpty() ? "" : "?" + queryParams);

            HttpURLConnection conn = (HttpURLConnection) new URL(fullUrl).openConnection();
            try {
                conn.setRequestMethod("GET");
                conn.setRequestProperty(AUTHORIZATION_HEADER, BEARER_PREFIX + token);
                conn.setRequestProperty("Accept", "application/json");
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(10000);

                try (BufferedReader br = new BufferedReader(
                        new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                    String response = br.lines().collect(Collectors.joining());
                    JSONObject jsonObject = JSONObject.parseObject(response);
                    TableDataInfo tableDataInfo = jsonObject.to(TableDataInfo.class);
                    if (tableDataInfo.getCode() == 401){
                        redisCache.deleteObject(TOKEN_EXPIRE_KEY);
                        TableDataInfo tableDataInfo1 = new TableDataInfo();
                        tableDataInfo1.setCode(601);
                        tableDataInfo1.setMsg("融合系统token过期,请刷新页面后重试！");
                        return tableDataInfo1 ;
                    }
                    return jsonObject.to(TableDataInfo.class);
                }
            } finally {
                conn.disconnect();
            }
        } catch (IOException e) {
            logger.error("Error while getting table data from fusion system", e);
            redisCache.deleteObject(TOKEN_EXPIRE_KEY);
            throw new RuntimeException("Failed to get table data from fusion system", e);
        }
    }

    /**
     * 发送GET请求(RestFul风格)
     *
     * @param path RestFul风格路径
     * @return 请求结果
     */
    public AjaxResult sendGetRestFulApi(String path) {
        String token = redisCache.getCacheObject(TOKEN_EXPIRE_KEY);
        if (token == null) {
            throw new IllegalStateException("Token not found in Redis");
        }

        try {
            String fullUrl = fusionUrl + path;
            HttpURLConnection conn = (HttpURLConnection) new URL(fullUrl).openConnection();
            try {
                conn.setRequestMethod("GET");
                conn.setRequestProperty(AUTHORIZATION_HEADER, BEARER_PREFIX + token);
                conn.setRequestProperty("Accept", "application/json");
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(10000);

                try (BufferedReader br = new BufferedReader(
                        new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                    String response = br.lines().collect(Collectors.joining());
                    return checkToken(response);
                }
            } finally {
                conn.disconnect();
            }
        } catch (IOException e) {
            logger.error("Error while getting table data from fusion system", e);
            throw new RuntimeException("Failed to get table data from fusion system", e);
        }
    }

    /**
     * 发送PUT请求
     *
     * @param path   请求路径
     * @param params 请求参数
     * @return 请求结果
     * @throws RuntimeException 异常信息
     */
    public AjaxResult sendPut(String path, Object params) throws RuntimeException {
        String token = redisCache.getCacheObject(TOKEN_EXPIRE_KEY);
        if (token == null) {
            throw new IllegalStateException("Token not found in Redis");
        }

        try {
            String fullUrl = fusionUrl + path;

            HttpURLConnection conn = (HttpURLConnection) new URL(fullUrl).openConnection();
            try {
                conn.setRequestMethod("PUT");
                conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
                conn.setDoOutput(true);  // 允许输出请求体
                conn.setRequestProperty(AUTHORIZATION_HEADER, BEARER_PREFIX + token);
                conn.setRequestProperty("Accept", "application/json");
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(10000);

                // 写入请求体
                try (OutputStream os = conn.getOutputStream()) {
                    byte[] input = JSONObject.toJSONString(params).getBytes(StandardCharsets.UTF_8);
                    os.write(input, 0, input.length);
                }

                // 处理响应
                try (BufferedReader br = new BufferedReader(
                        new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                    String response = br.lines().collect(Collectors.joining());
                    return checkToken(response);
                }
            } finally {
                conn.disconnect();
            }
        } catch (IOException e) {
            logger.error("Error while sending PUT request to fusion system", e);
            throw new RuntimeException("Failed to send PUT request to fusion system", e);
        }
    }

    /**
     * 发送GET请求结果List
     *
     * @param path   请求路径
     * @param params 请求参数
     * @return 请求结果
     * @throws RuntimeException 异常信息
     */
    public AjaxResult sendGet(String path, Object params) throws RuntimeException {
        String token = redisCache.getCacheObject(TOKEN_EXPIRE_KEY);
        if (token == null) {
            throw new IllegalStateException("Token not found in Redis");
        }

        try {
            String queryParams = convertToQueryString(params);
            logger.debug("Request parameters: {}", queryParams);

            String fullUrl = fusionUrl + path + (queryParams.isEmpty() ? "" : "?" + queryParams);
            HttpURLConnection conn = (HttpURLConnection) new URL(fullUrl).openConnection();
            try {
                conn.setRequestMethod("GET");
                conn.setRequestProperty(AUTHORIZATION_HEADER, BEARER_PREFIX + token);
                conn.setRequestProperty("Accept", "application/json");
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(10000);

                // 处理响应
                try (BufferedReader br = new BufferedReader(
                        new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                    String response = br.lines().collect(Collectors.joining());
                    return checkToken(response);
                }
            } finally {
                conn.disconnect();
            }
        } catch (IOException e) {
            logger.error("Error while sending PUT request to fusion system", e);
            throw new RuntimeException("Failed to send PUT request to fusion system", e);
        }
    }

    /**
     * 发送POST请求
     *
     * @param path        请求路径
     * @param headers     请求头信息
     * @param requestBody 请求体
     * @param contentType 请求体类型
     * @return 请求结果
     * @throws IOException IO 异常
     */
    public AjaxResult sendPostRequest(String path, Map<String, String> headers,
                                      String requestBody, String contentType) throws IOException {
        String token = redisCache.getCacheObject(TOKEN_KEY);
        if (token == null) {
            throw new IllegalStateException("Token not found in Redis");
        }

        URL url = new URL(fusionUrl + path);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        try {
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);

            // Set default headers
            connection.setRequestProperty(AUTHORIZATION_HEADER, BEARER_PREFIX + token);
            connection.setRequestProperty(CONTENT_TYPE_HEADER, contentType);

            // Add custom headers if provided
            if (headers != null) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    connection.setRequestProperty(entry.getKey(), entry.getValue());
                }
            }

            // Write request body if provided
            if (requestBody != null) {
                try (OutputStream outputStream = connection.getOutputStream();
                     OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
                    writer.write(requestBody);
                    writer.flush();
                }
            }

            // Read response
            try (BufferedReader in = new BufferedReader(
                    new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
                StringBuilder response = new StringBuilder();
                String inputLine;
                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }

                logger.debug("Response from fusion system: {}", response);
                return checkToken(response.toString());
            }

        } finally {
            connection.disconnect();
        }
    }

    /**
     * 发送DELETE请求
     *
     * @param path        请求路径
     * @param headers     请求头
     * @param requestBody 请求参数
     * @param contentType 请求体类型
     * @return 操作结果
     * @throws IOException 异常信息
     */
    public AjaxResult sendDeleteRequest(String path, Map<String, String> headers, String requestBody, String contentType) throws IOException {
        String token = redisCache.getCacheObject(TOKEN_KEY);
        if (token == null) {
            throw new IllegalStateException("Token not found in Redis");
        }

        URL url = new URL(fusionUrl + path);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        try {
            connection.setRequestMethod("DELETE");  // 改为 DELETE 方法
            connection.setDoOutput(true);  // 允许输出请求体（可选，DELETE 也可以带 body）

            // 设置默认请求头
            connection.setRequestProperty(AUTHORIZATION_HEADER, BEARER_PREFIX + token);
            if (contentType != null) {
                connection.setRequestProperty(CONTENT_TYPE_HEADER, contentType);
            }

            // 添加自定义请求头（如果有）
            if (headers != null) {
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    connection.setRequestProperty(entry.getKey(), entry.getValue());
                }
            }

            // 写入请求体（DELETE 也可以带 body，如 Elasticsearch 的删除查询）
            if (requestBody != null) {
                try (OutputStream outputStream = connection.getOutputStream();
                     OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
                    writer.write(requestBody);
                    writer.flush();
                }
            }

            // 读取响应
            try (BufferedReader in = new BufferedReader(
                    new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
                StringBuilder response = new StringBuilder();
                String inputLine;
                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }

                logger.debug("Response from fusion system: {}", response);
                return checkToken(response.toString());
            }

        } finally {
            connection.disconnect();
        }
    }

    /**
     * 将对象转换为URL编码的查询字符串
     */
    private String convertToQueryString(Object queryParam) throws UnsupportedEncodingException {
        if (queryParam == null) {
            return "";
        }

        StringBuilder result = new StringBuilder();
        Field[] declaredFields = queryParam.getClass().getDeclaredFields();

        for (Field field : declaredFields) {
            field.setAccessible(true);

            try {
                String name = field.getName();
                Object value = field.get(queryParam);

                if (value != null) {
                    String encodedValue = URLEncoder.encode(value.toString(), StandardCharsets.UTF_8.name());

                    if (result.length() > 0) {
                        result.append("&");
                    }
                    result.append(name).append("=").append(encodedValue);
                }
            } catch (IllegalAccessException e) {
                logger.warn("Failed to access field: {}", field.getName(), e);
            }
        }

        return result.toString();
    }


    /**
     * 读取错误响应信息
     */
    private String readErrorResponse(HttpURLConnection connection) {
        try (InputStream errorStream = connection.getErrorStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream, StandardCharsets.UTF_8))) {

            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            return response.toString();
        } catch (IOException e) {
            logger.warn("Failed to read error response", e);
            return "No error details available";
        }
    }

    /**
     * 检查Token
     */
    private AjaxResult checkToken(String response) {
        AjaxResult ajaxResult = JSONObject.parseObject(response, AjaxResult.class);
        if (ajaxResult.get("code").equals(401)) {
            redisCache.deleteObject(TOKEN_KEY);
           return AjaxResult.warn("融合系统token过期，请刷新页面后重试！");
        }
        return ajaxResult;
    }
}